package com.dynamic.mybatis.core.parser.field;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.NumberUtil;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.dynamic.mybatis.core.enums.CommandType;
import com.dynamic.mybatis.core.enums.Type;
import com.dynamic.mybatis.core.exceptions.MybatisFieldValidateException;
import com.dynamic.mybatis.core.metadata.MappedStatementFieldValidator;
import com.dynamic.mybatis.core.metadata.MappedStatementMetaField;
import com.dynamic.mybatis.core.parser.field.DynamicMappedStatementInputParameterFieldParser;
import com.dynamic.mybatis.core.session.DynamicSqlSession;
import org.apache.ibatis.ognl.Ognl;
import org.apache.ibatis.ognl.OgnlException;
import org.apache.ibatis.session.Configuration;

import java.util.*;

public abstract class DynamicMappedStatementFieldValidator extends DynamicMappedStatementInputParameterFieldParser {

    public DynamicMappedStatementFieldValidator(DynamicSqlSession dynamicSqlSession) {
        super(dynamicSqlSession);
    }

    public Object validate(List<MappedStatementMetaField> field, CommandType commandType, Object rootParameter, Object parameter) {
        if (CollectionUtils.isEmpty(field)) {
            return null;
        }
        return validate(field.get(0), commandType, rootParameter, parameter);
    }


    public Object validate(MappedStatementMetaField field, CommandType commandType, Object rootParameter, Object parameter) {
        if (field == null) {
            return null;
        }
        return validate(field, null, commandType, rootParameter, parameter);
    }

    public Object validate(MappedStatementMetaField field, String type, CommandType commandType, Object rootParameter, Object parameter) {
        MappedStatementFieldValidator validator = field.getValidator();
        if (validator == null || !validator.isEnable()) {
            return null;
        }
        if (validator.isRequired() && StringUtils.checkValNull(parameter)
                && !(field.isAutoincrement() && commandType == CommandType.StandardCommand.INSERT)
        ) {
            throw new MybatisFieldValidateException(field, StringUtils.isNotBlank(validator.getErrorMsg()) ? validator.getErrorMsg() : "%s不能为空！");
        }
        if (parameter == null) {
            return null;
        }

        type = StringUtils.isNotBlank(type) ? type : field.getType();

        if (type == Type.StandardType.VARCHAR.javaTypeAlias) {//字符

            if (parameter != null && !(parameter instanceof String)) {

                throw new MybatisFieldValidateException(field, StringUtils.isNotBlank(validator.getErrorMsg()) ? validator.getErrorMsg() : "%s必须为字符！");

            } else if (field.getValidator().getMinLength() != null && ((String) parameter).length() < field.getValidator().getMinLength().longValue()) {

                throw new MybatisFieldValidateException(field, StringUtils.isNotBlank(validator.getErrorMsg()) ? validator.getErrorMsg() : "%s最小长度为" + field.getValidator().getMinLength().longValue());

            } else if (field.getValidator().getMaxLength() != null && ((String) parameter).length() > field.getValidator().getMinLength().longValue()) {

                throw new MybatisFieldValidateException(field, StringUtils.isNotBlank(validator.getErrorMsg()) ? validator.getErrorMsg() : "%s最大长度为" + field.getValidator().getMinLength().longValue());
            }

        } else if (Type.NUMBER_TYPES.contains(type)) {//数字
            boolean transport;
            if (transport = parameter instanceof String) {
                try {
                    parameter = NumberUtil.parseNumber((String) parameter);
                } catch (Exception e) {
                    throw new MybatisFieldValidateException(field, StringUtils.isNotBlank(validator.getErrorMsg()) ? validator.getErrorMsg() : "%s必须为数字！");
                }
            }

            if (!(parameter instanceof Number)) {

                throw new MybatisFieldValidateException(field, StringUtils.isNotBlank(validator.getErrorMsg()) ? validator.getErrorMsg() : "%s必须为数字！");

            } else if (field.getValidator().isDigits() && Objects.equals(((Number) parameter).longValue(), parameter)) {

                throw new MybatisFieldValidateException(field, StringUtils.isNotBlank(validator.getErrorMsg()) ? validator.getErrorMsg() : "%s必须为整数！");

            } else if (field.getValidator().getMin() != null && NumberUtil.compare(((Number) parameter).doubleValue(), field.getValidator().getMin().doubleValue()) < 0) {

                throw new MybatisFieldValidateException(field, StringUtils.isNotBlank(validator.getErrorMsg()) ? validator.getErrorMsg() : "%s最小值为" + field.getValidator().getMin());

            } else if (field.getValidator().getMax() != null && NumberUtil.compare(((Number) parameter).doubleValue(), field.getValidator().getMax().doubleValue()) > 0) {

                throw new MybatisFieldValidateException(field, StringUtils.isNotBlank(validator.getErrorMsg()) ? validator.getErrorMsg() : "%s最大值为" + field.getValidator().getMax());
            }

            if (transport) {
                return parameter;
            }

        } else if (Type.DATE_TIME_TYPES.contains(type) && parameter instanceof String) {//日期、时间

            try {
                return DateUtil.parse((String) parameter, validator.getDatePattern());
            } catch (Exception e) {
                throw new MybatisFieldValidateException(field, StringUtils.isNotBlank(validator.getErrorMsg()) ? validator.getErrorMsg() : "  " + parameter + " " + validator.getDatePattern() + " " + " %s格式有误！");
            }

        } else if (CollectionUtils.isNotEmpty(validator.getEnums()) && !validator.getEnums().containsKey(parameter)) {

            throw new MybatisFieldValidateException(field, StringUtils.isNotBlank(validator.getErrorMsg()) ? validator.getErrorMsg() : "%s未在指定的枚举范围！");

        } else if (Objects.equals(type, Type.StandardType.STRUCT.javaTypeAlias)) { //对象
            if (!(parameter instanceof Map)) {

                throw new MybatisFieldValidateException(field, StringUtils.isNotBlank(validator.getErrorMsg()) ? validator.getErrorMsg() : "%s必须为结构体！");
            }
            if (CollectionUtils.isNotEmpty(field.getChildren())) {
                for (MappedStatementMetaField child : field.getChildren()) {
                    Object result = validate(child, child.getGenericType(), commandType, rootParameter, ((Map) parameter).get(child.getField()));
                    if (result != null) {
                        ((Map) parameter).put(child.getField(), result);
                    }
                }
            }

        } else if (Objects.equals(type, Type.StandardType.ARRAY.javaTypeAlias)) {//数组

            if (parameter != null && !(parameter instanceof Collection)) {

                throw new MybatisFieldValidateException(field, StringUtils.isNotBlank(validator.getErrorMsg()) ? validator.getErrorMsg() : "%s必须为数组！");

            } else if (field.getValidator().getMinLength() != null && ((Collection) parameter).size() < field.getValidator().getMinLength().longValue()) {

                throw new MybatisFieldValidateException(field, StringUtils.isNotBlank(validator.getErrorMsg()) ? validator.getErrorMsg() : "%s最小长度为" + field.getValidator().getMinLength().longValue());

            } else if (field.getValidator().getMaxLength() != null && ((Collection) parameter).size() > field.getValidator().getMinLength().longValue()) {

                throw new MybatisFieldValidateException(field, StringUtils.isNotBlank(validator.getErrorMsg()) ? validator.getErrorMsg() : "%s最大长度为" + field.getValidator().getMinLength().longValue());
            }

            List list = ((List) parameter);
            for (int i = 0; i < list.size(); i++) {
                Object result = validate(field, field.getGenericType(), commandType, rootParameter, list.get(i));
                if (result != null) {
                    ((List) parameter).set(i, result);
                }
            }
        } else if (validator.getRegexPattern() != null && !validator.getRegexPattern().matcher(Objects.toString(parameter, null)).matches()) {//正则校验

            throw new MybatisFieldValidateException(field, "%s" + Objects.toString(validator.getErrorMsg(), "校验失败"));

        } else if (validator.getOgnlExpression() != null) { //ognl校验
            try {
                Ognl.getValue(validator.getOgnlExpression(), rootParameter);
            } catch (Exception e) {
                throw new MybatisFieldValidateException(field, "%s" + Objects.toString(validator.getErrorMsg(), "校验失败"));
            }
        }
        return null;
    }

    public static void main(String[] args) throws OgnlException {
        Map context = new HashMap();
        context.put("a", 1);
        Object value = Ognl.getValue("a", context);


        Map context1 = new HashMap();
        List<Map<String, Object>> ls = new ArrayList();

        Map fc = new HashMap();
        fc.put("a", "A01");
        fc.put("b", "B01");
        fc.put("c", "C01");
        ls.add(fc);

        Map fc2 = new HashMap();
        fc2.put("a", "A02");
        fc2.put("b", "B02");
        fc2.put("c", "C02");
        ls.add(fc2);

        context1.put("list1", ls);

        String val = "B02";
        Object obj = Ognl.getValue(Ognl.parseExpression("list1.{?#this.a.equals(\"A01\") || #this.b==" + val + "}"), context1);
        System.out.println(obj);
    }


}
